﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;

namespace DevMetro.oDesk
{
    public class oDeskClient        
    {
        public string ConsumerKey { get; set; }
        public string ConsumerSecret { get; set; }

        private string GetSignature(string sigBaseString, string consumerSecretKey)
        {
            IBuffer KeyMaterial = CryptographicBuffer.ConvertStringToBinary(consumerSecretKey + "&", BinaryStringEncoding.Utf8);
            MacAlgorithmProvider HmacSha1Provider = MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA1");
            CryptographicKey MacKey = HmacSha1Provider.CreateKey(KeyMaterial);
            IBuffer DataToBeSigned = CryptographicBuffer.ConvertStringToBinary(sigBaseString, BinaryStringEncoding.Utf8);
            IBuffer SignatureBuffer = CryptographicEngine.Sign(MacKey, DataToBeSigned);
            string Signature = CryptographicBuffer.EncodeToBase64String(SignatureBuffer);

            return Signature;
        }

        private string GetNonce()
        {
            Random rand = new Random();
            int nonce = rand.Next(1000000000);
            return nonce.ToString();
        }

        private string GetTimeStamp()
        {
            TimeSpan SinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
            return Math.Round(SinceEpoch.TotalSeconds).ToString();
        }

        public async Task<OAuthResponse> GetRequestTokenAsync()
        {
            try
            {
                var client = new HttpClient();
                var values = new List<KeyValuePair<string, string>>();               
                var nonce = GetNonce();
                var timeStamp = GetTimeStamp();
                var requestTockenUrl = "https://www.odesk.com/api/auth/v1/oauth/token/request";

                values.Add(new KeyValuePair<string, string>("oauth_consumer_key", ConsumerKey));
                values.Add(new KeyValuePair<string, string>("oauth_nonce", nonce));
                values.Add(new KeyValuePair<string, string>("oauth_signature_method", "HMAC-SHA1"));
                values.Add(new KeyValuePair<string, string>("oauth_timestamp", timeStamp));
                values.Add(new KeyValuePair<string, string>("oauth_version", "1.0"));

                StringBuilder signatureParams = new StringBuilder();
                signatureParams.AppendFormat("oauth_consumer_key={0}&", ConsumerKey);
                signatureParams.AppendFormat("oauth_nonce={0}&", nonce);
                signatureParams.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
                signatureParams.AppendFormat("oauth_timestamp={0}&", timeStamp);
                signatureParams.AppendFormat("oauth_version={0}", "1.0");

                var signature = GetSignature("POST&" + Uri.EscapeDataString(requestTockenUrl) + "&" + Uri.EscapeDataString(signatureParams.ToString()), ConsumerSecret);
                values.Add(new KeyValuePair<string, string>("oauth_signature", Uri.EscapeDataString(signature)));                

                var content = new FormUrlEncodedContent(values);

                string authorizationHeaderParams = "realm=\"\",oauth_version=\"1.0\",oauth_consumer_key=\"" + ConsumerKey + "\",oauth_timestamp=\"" + timeStamp + "\",oauth_nonce=\"" + nonce + "\",oauth_signature_method=\"HMAC-SHA1\",oauth_signature=\"" + Uri.EscapeDataString(signature) + "\"";                
                client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("OAuth", authorizationHeaderParams);
                var data = await client.PostAsync("https://www.odesk.com/api/auth/v1/oauth/token/request", content);

                var respnse = new OAuthResponse();

                if (data.IsSuccessStatusCode)
                {
                    var returnString = await data.Content.ReadAsStringAsync();
                    var returnValues = returnString.Split('&');
                    respnse.OAuthCallbackConfirmed = returnValues.FirstOrDefault(x => x.Contains("oauth_callback_confirmed")).Split('=')[1] == "true";
                    respnse.OAuthToken = returnValues.FirstOrDefault(x => x.Contains("oauth_token")).Split('=')[1];
                    respnse.OAuthTokenSecret = returnValues.FirstOrDefault(x => x.Contains("oauth_token_secret")).Split('=')[1];
                }
                else
                {
                    respnse.Error = await data.Content.ReadAsStringAsync();
                }

                return respnse;
                
            }
            catch (Exception ex)
            {
                var respnse = new OAuthResponse();
                respnse.Error = ex.Message;
                return respnse;
            }
        }

        public Uri GetAuthUri(string oAuthToken)
        {
            return new Uri(string.Format("https://www.odesk.com/services/api/auth?oauth_token={0}", oAuthToken));
        }

        /// <summary>
        /// Return detailed info about current authenticated user and some data from his/her profile.
        /// </summary>
        /// <returns></returns>
        public async Task<MyInfo> GetMyInfoAsync()
        {
            try
            {
                var client = new HttpClient();
                var data = await client.GetStringAsync("https://www.odesk.com/api/auth/v1/info.xml");
                var serializer = new XmlSerializer(typeof(MyInfo));
                var myInfo = (MyInfo)serializer.Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(data)));
                return myInfo;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public List<TeamRoom> GetTeamRooms()
        {
            throw new NotImplementedException();
        }

        public TeamRoom GetTeamRoomByCompany()
        {
            throw new NotImplementedException();            
        }
    }
}
